/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { defineComponent, SetupContext, ref, computed, watch, onMounted, toRefs, onBeforeMount } from 'vue';
import { colorPickerProps, ColorPickerProps } from './color-picker.props';
import { ColorPickerControl, ColorType } from './composition/class/control.class';
import { getValueByType } from './composition/class/helper.functions';
import { Color } from './composition/class/color.class';
import SvPanel from './composition/component/sv-panel';
import Hue from './composition/component/hue';
import Alpha from './composition/component/alpha';
import Preset from './composition/component/preset';
import './composition/component/scss/color-picker.scss';

export default defineComponent({
    name: 'FColorPicker',
    props: colorPickerProps,
    emits: ['valueChanged', 'activeChange', 'update:color', 'update:hue'] as string[] | undefined,
    setup(props: ColorPickerProps, context: SetupContext) {
        /** 新颜色对象,包括hsva等值变化*/
        const colorObject = ref(new Color(props.color));
        /** 当前颜色 */
        const colorRef = ref(props.color);
        /** 是否禁用该组件 */
        const disabled = ref(props.disabled);
        /** 上一个颜色 */
        const preColor = ref(props.color);
        /** 是否只读 */
        const editable = ref(props.editable);
        /** 是否允许为空 */
        const allowColorNull = ref(props.allowColorNull);
        /** 用户传入的自定义内置颜色 */
        const presets = ref(props.presets);
        /** 是否展示颜色选择器panel */
        const isShowPanel = ref(false);
        /** 是否展示下方透明度点击条 */
        const showAlpha = ref(false);
        /** 判断是否已经修改过颜色 */
        const firstCommit = ref(false);
        /** 展示HEX或RGBA */
        const presetColorTypeText = ref('HEX');
        /** 随机id */
        const randomId: string = Math.floor(Math.random() * 1000).toString();
        /** 索引值：用来计算当前展示HEX或RGBA */
        let currentColorTypeIndex = -1;
        /** 颜色种类：hex或rgba */
        let _colorFormat: ColorType;
        /** 创建新颜色对象 */
        let control = new ColorPickerControl('#000000');
        /** 存储初始值 */
        const originalColor = ref(props.color);
        let colorPickerPanelId: HTMLElement;
        let colorPickerPanelSureID: HTMLElement;
        const trigger = ref<HTMLDivElement | null>(null);
        const elementRef = ref<HTMLDivElement | null>(null);
        const pickerPanelRef = ref<HTMLDivElement | null>(null);

        /** _colorFormat: hex/rgba */
        let colorFormat = computed(() => {
            if (!_colorFormat) {
                if (control && control.initType) {
                    return control.initType;
                }
            }
            return _colorFormat;
        });
        /** 内部输入框显示的颜色值 */

        const currentColor = computed({
            get() {
                if (_colorFormat && colorRef.value !== null) {
                    findColorType(_colorFormat);
                    return getValueByType(new Color(colorRef.value), ColorType[_colorFormat]);
                }
                return colorRef.value;
            },
            set(newColor: string) {
                if (newColor !== null) {
                    resetColorValue(newColor);
                    inputValueChange(newColor);
                }
            }
        });
        /** 输入框显示值 */
        const inputValue: any = ref(currentColor.value);

        /** 是否展示preset */
        const showPreset = computed(() => {
            if (currentColorTypeIndex > -1) {
                return true;
            }
            return false;
        });

        /** 是否展示内部输入框分类：如hex及rgba */
        const showCurrentColorTypeIndex = computed(() => {
            if (presets.value.length > 0) {
                return true;
            }
            return false;
        });

        const colorTriggerStyle = computed(() => {
            const styleObject = {
                'background-color': preColor.value
            } as Record<string, any>;
            return styleObject;
        });

        const ifShowAlpha = computed(() => {
            const hiddenStyle = showAlpha.value && isShowPanel.value ? 'visibility:visible' : 'visibility:hidden';
            return hiddenStyle;
        });

        const presetColorType = [
            {
                text: 'HEX',
                type: ColorType.hex
            },
            {
                text: 'RGBA',
                type: ColorType.rgba
            }
        ];

        /** 为每个颜色选择器增加专属id */
        function addIdentification() {
            const colorPickerPanel = document.getElementById('farris-color-picker-panel') as HTMLElement;
            colorPickerPanel.id = `farris-color-picker-panel-${randomId}`;

            const colorPickerPanelSure = document.getElementById('farris-color-picker-plus-sure') as HTMLElement;
            colorPickerPanelSure.id = `farris-color-picker-plus-sure-${randomId}`;

            const colorPickerPanelInput = document.getElementById('farris-color-picker-plus-input') as HTMLElement;
            colorPickerPanelInput.id = `farris-color-picker-plus-input-${randomId}`;

            colorPickerPanelSureID = document.getElementById(`farris-color-picker-plus-sure-${randomId}`) as HTMLElement;
            colorPickerPanelId = document.getElementById(`farris-color-picker-panel-${randomId}`) as HTMLElement;
            colorPickerPanelId.className = 'color-picker-panel disabled';
        }


        /** 判断初始值是否为空 */
        function ifColorNull() {
            // 不允许为空时，标红处理
            if (!allowColorNull.value && !colorRef.value) {
                const colorPickerPanelSure = document.getElementById(`farris-color-picker-plus-sure-${randomId}`) as HTMLElement;
                colorPickerPanelSure.classList.toggle('disabled');
                const isCommitBtnNull = document.getElementById(`farris-color-picker-plus-input-${randomId}`) as HTMLElement;
                isCommitBtnNull.style.borderColor = 'red';
            }
        }
        /** 初始化颜色选择器 */
        /** 初始化颜色选择器 */
        function initialColorControl() {
            if (colorRef.value) {
                resetColorValue(colorRef.value);
                // color为空，但允许为空，跳过
                if (!(!colorRef.value && allowColorNull.value)) {
                    colorRef.value = getValueByType(new Color(colorRef.value), ColorType[colorFormat.value]);
                }
                inputValue.value = currentColor.value;
            }
            handlePresetColorType(findColorType(control.initType));
        }
        /** 设置颜色值和颜色预设 */
        function setColorAndPreset() {
            if (colorRef.value) {
                resetColorValue(colorRef.value);
            }
            if (!control.hasPresets()) {
                control.setColorPresets(presets.value);
            }
            if (colorRef.value) {
                preColor.value = getValueByType(new Color(colorRef.value), ColorType[colorFormat.value]);
            }
            // 允许值为空
            else if (!colorRef.value && allowColorNull.value) {
                preColor.value = null;
            }
        }
        /** 修改内部输入框颜色值 */
        function modifyInputValue() {
            control.valueChanges.subscribe((value) => {
                const newColorValue = getValueByType(value, ColorType[_colorFormat || control.initType]);
                colorRef.value = newColorValue;
            });
        }

        /** 根据index确定颜色类别，如：HEX,RGBA */
        function handlePresetColorType(currentColorTypeIndex: number) {
            presetColorTypeText.value = presetColorType[currentColorTypeIndex].text;
        }

        /** 是否显示透明度条 */
        function ifShowAlphaBar() {
            showAlpha.value = !!(_colorFormat?.includes('a') || control.initType?.includes('a'));
        }

        onBeforeMount(() => {
            control.setColorPresets(presets.value || ['#eaecf3']);
        });

        onMounted(() => {
            addIdentification();
            ifColorNull();
            initialColorControl();
            setColorAndPreset();
        });

        /** 切换颜色类别 */
        watch(presetColorTypeText, () => {
            // 计算内部输入框显示值
            modifyInputValue();
            currentColor.value = getValueByType(new Color(colorRef.value), ColorType[_colorFormat || control.initType]);
            colorObject.value = new Color(currentColor.value);
            ifShowAlphaBar();
        });

        /** 计算出的颜色值 */
        watch(colorRef, (newValue: any) => {
            // 计算颜色值
            if (getValueByType(control.value, control.initType) !== newValue && newValue !== null) {
                resetColorValue(newValue);
            }
            // 确定颜色所属的类别，如HEX/RGBA
            handlePresetColorType(findColorType(control.initType));
        });

        /** 通过用户切换的colorObject（hsva等值变化）计算出当前颜色值 */
        watch(colorObject, (newColor: any) => {
            colorRef.value = getValueByType(newColor, ColorType[_colorFormat || control.initType]);
            resetColorValue(colorRef.value);
            currentColor.value = colorRef.value;
        });

        /** 外部输入框内容变化 */
        function inputValueChange(value: any) {
            const colorPickerPanelInputID = document.getElementById(`farris-color-picker-plus-input-${randomId}`) as HTMLElement;

            if ((value == '' || value == undefined || value == null) && !allowColorNull.value) {
                colorRef.value = null;
                colorPickerPanelInputID.style.borderColor = 'red';
                colorPickerPanelSureID.className = 'btn btn-secondary disabled';
            } else {
                colorPickerPanelInputID.style.borderColor = '#dcdfe6';
                colorPickerPanelSureID.className = 'btn btn-secondary';
            }
        }
        /** 提交颜色变化 */
        function commit(): void {
            // 如果允许为空
            if (allowColorNull.value) {
                preColor.value = colorRef?.value ?? null;
                const outputValue = {
                    elementValue: preColor
                };
                context.emit('valueChanged', outputValue);
                colorPickerPanelId.classList.toggle('disabled');
            }
            // 如果不允许为空
            if (!allowColorNull.value) {
                // 颜色值不为空
                if (!(currentColor.value == undefined || currentColor.value == null || currentColor.value == '')) {
                    trigger.value?.style?.setProperty('background', colorRef.value);
                    firstCommit.value = true;
                    preColor.value = colorRef.value;
                    const outputValue = {
                        elementValue: preColor
                    };
                    context.emit('valueChanged', outputValue);
                    colorPickerPanelId.classList.toggle('disabled');
                }
            }

            // 初始值为空，且无操作，且允许为空，可以直接点击确认关闭
            if (!originalColor.value && !colorRef.value && !firstCommit.value && allowColorNull) {
                colorPickerPanelId.classList.toggle('disabled');
            }
            inputValueChange(colorRef.value);
            currentColor.value = colorRef.value;
            if (!colorPickerPanelSureID.classList.contains('disabled')) {
                inputValue.value = colorRef.value;
                isShowPanel.value = false;
            }
        }

        /** 切换HEX和RGBA时，重新计算color值 */
        function resetColorValue(newColor: string) {
            control?.setValueFrom(newColor, randomId, allowColorNull.value);
        }
        /** 展示色盘等panel区域 */
        function toggleShowPanel(e: any): void {
            if (disabled.value) {
                return;
            }
            isShowPanel.value = true;
            colorPickerPanelId.classList.toggle('disabled');
            ifColorNull();
            resetColorValue(colorRef.value);
        }

        /** 找到颜色对应分类，如：HEX.RGBA */
        function findColorType(typeStr: any) {
            const findTypeIndex = presetColorType.findIndex((item) => item.type === typeStr);
            currentColorTypeIndex = findTypeIndex;
            return findTypeIndex;
        }

        /** 点击上下箭头后，切换HEX和RGBA */
        function changeColorFormatByIcon(direction: string) {
            if (!colorPickerPanelSureID.classList.contains('disabled')) {
                const total = presetColorType.length;
                currentColorTypeIndex = (total + currentColorTypeIndex + (direction === 'up' ? 1 : -1)) % total;
                _colorFormat = presetColorType[currentColorTypeIndex].type;
                handlePresetColorType(currentColorTypeIndex);
                resetColorValue(colorRef.value);
            }
        }

        return () => {
            return (
                <div class="f-color-picker-component" ref={elementRef}>
                    <div
                        class={['color-picker-panel', { disabled: disabled.value }]}
                        id="farris-color-picker-panel"
                        ref={pickerPanelRef}
                        onClick={(event) => event.stopPropagation}
                        style="top:30px">
                        <div class="color-picker-main">
                            <Hue v-model:hue={control.hue} allowColorNull={allowColorNull.value} v-model:color={colorObject.value}></Hue>
                            <SvPanel
                                randomId={randomId}
                                v-model:hue={control.hue}
                                allowColorNull={allowColorNull.value}
                                v-model:color={colorObject.value}></SvPanel>
                        </div>
                        <Alpha
                            style={ifShowAlpha.value}
                            randomId={randomId}
                            allowColorNull={allowColorNull.value}
                            v-model:color={colorObject.value}></Alpha>
                        <div class="input-btn" style="display:flex;align-items: center;">
                            <span v-show={showCurrentColorTypeIndex} style="width:40px;margin-right:10px;">
                                {presetColorTypeText.value}
                            </span>
                            <input type="text" id="farris-color-picker-plus-input" v-model={currentColor.value} style="float:none" />
                            <div class="type-icon-btn-wrapper" style="cursor:pointer" v-show={showCurrentColorTypeIndex}>
                                <span class="f-icon f-icon-arrow-60-up type-icon-btn" onClick={() => changeColorFormatByIcon('up')}></span>
                                <span
                                    class="f-icon f-icon-arrow-60-down type-icon-btn"
                                    onClick={() => changeColorFormatByIcon('down')}></span>
                            </div>
                            <div class="input-btn">
                                <button id="farris-color-picker-plus-sure" class="btn btn-secondary" onClick={commit}>
                                    确定
                                </button>
                            </div>
                        </div>
                        <Preset
                            v-model:color={colorObject.value}
                            colorPresets={control.presets}
                            v-model:hue={control.hue}
                            randomId={randomId}
                            v-show={showPreset}></Preset>
                    </div>
                    <div class="color-picker-wrapper">
                        <input
                            type="text"
                            class="color-picker-input form-control"
                            value={inputValue.value}
                            readonly={props.editable || props.disabled}
                            onClick={(event) => event.stopPropagation()}
                        />
                        <div class="color-picker-trigger" onClick={toggleShowPanel}>
                            <div class="color-picker-trigger-inner">
                                <div style={colorTriggerStyle.value}></div>
                            </div>
                        </div>
                    </div>
                </div>
            );
        };
    }
});
